﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;
using Kokomo.Lexical.Expressions;

namespace Kokomo.PeInspector.Reflection.Disassembly.Flow
{
	class ConstructorFlowAnalyzer : MethodFlowAnalyzer
	{
		public ConstructorFlowAnalyzer(MsilDecompilationContext context, int length)
			: base(context, length)
		{
		}

		public ConstructorInfo Constructor { get; private set; }
		public IEnumerable<Expression> ConstructorArguments { get; private set; }
		public bool InitializesObject { get; private set; }

		protected override void AnalyzeInstruction()
		{
			MsilDecompilationContext context = this.Context;
			Instruction instruction = context.CurrentInstruction;

			if (
				(
					(instruction.OpCode == OpCodes.Call)
					&& (instruction.Operand is ConstructorInfo)
					)
				)
			{
				ConstructorInfo constructor = (ConstructorInfo)instruction.Operand;
				Expression instance = context.PeekExpression(constructor.GetParameters().Count());

				if (instance is InstanceReferenceExpression)
				{
					int parameterCount = constructor.GetParameters().Length;
					Expression[] arguments = new Expression[parameterCount];
					for (int i = parameterCount - 1; i >= 0; i--)
					{
						arguments[i] = context.PopExpression();
					}
					this.ConstructorArguments = arguments;
					this.Constructor = constructor;

					context.Advance();
				}
				else
				{
					base.AnalyzeInstruction();
				}
			}
			else if (
			  (instruction.OpCode == OpCodes.Initobj)
			  && (this.Context.PeekExpression() is InstanceReferenceExpression)
			  )
			{
				context.PopExpression();
				context.Advance();
				this.InitializesObject = true;
			}
			else
			{
				base.AnalyzeInstruction();
			}
		}
	}
}
